﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Security.Principal;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using LynxWiki.Infrastructure;
using LynxWiki.Search;

[assembly: InternalsVisibleTo("LynxWiki.Tests")]

namespace LynxWiki.Repository
{
    public class WikiDiscussRepository : LynxWiki.Infrastructure.IWikiTopicRepository
    {
        private string server_path;
        private string root;
        private string path;
        private string currentDir;
        private IPrincipal user;

        public WikiDiscussRepository(string root, string path, string currentDir, IPrincipal user = null)
        {
            this.root = root;
            if (path != null) {
                this.path = path;
            }
            else {
                this.path = string.Empty;
            }
            if (currentDir != null) {
                this.currentDir = currentDir;
            }
            else {
                this.currentDir = string.Empty;
            }
            this.user = user;
        }

        public string WikiDir
        {
            get
            {
                if (currentDir == "WikiDir") {
                    return root;
                }
                else {
                    return path;
                }
            }
        }

        public WikiDiscussRepository(string fullPath, IPrincipal user = null)
        {
            this.root = DomainModel.WikiRoot.RootDirectory;
            int server_part = fullPath.LastIndexOf("LynxWiki");
            server_path = fullPath.Substring(0, server_part + 8);
            int startPath = root.Length;
            this.path = string.Empty;
            int endPath = fullPath.LastIndexOf(@"\") + 1;
            if (endPath - startPath > server_part) {
                this.path = fullPath.Substring(fullPath.LastIndexOf(this.root));
            }
            this.currentDir = string.Empty;
            if (endPath > 3) {
                this.currentDir = fullPath.Substring(endPath);
            }
            this.user = user;
        }

        internal WikiDiscussRepository(string root, string server_path, string path, string current_dir, IPrincipal user = null)
        {
            this.root = root;
            this.server_path = server_path;
            this.path = path;
            this.currentDir = current_dir;
            this.user = user;
        }


        public IEnumerable<DomainModel.TopicVersion> GetTopicVersions(string pageName)
        {
            DirectoryInfo dir;
            if (currentDir == "WikiDir" && path == string.Empty)
                dir = new DirectoryInfo(Path.Combine(server_path, root));
            else
                dir = new DirectoryInfo(Path.Combine(server_path, path));
            if (dir.Exists) {
                IEnumerable<FileInfo> query = from FileInfo file in dir.GetFiles()
                                              where file.Name.StartsWith(pageName + "__vd") select file;
                foreach (FileInfo file in query) {
                    yield return new DomainModel.TopicVersion(File.ReadAllText(file.FullName));
                }
            }
            yield break;
        }

        public int GetTopicVersionCount(string pageName)
        {
            int cnt = 0;
            DirectoryInfo dir;
            if (currentDir == "WikiDir" && path == string.Empty)
                dir = new DirectoryInfo(Path.Combine(server_path, root));
            else
                dir = new DirectoryInfo(Path.Combine(server_path, path));
            if (dir.Exists) {
                cnt = (from FileInfo file in dir.GetFiles() where file.Name == (pageName + "__discuss.xml") select file).Count();
            }
            return cnt;
        }

        public void Add(DomainModel.TopicVersion tv)
        {
            DirectoryInfo dir;
            if (currentDir == "WikiDir" && path == string.Empty)
                dir = new DirectoryInfo(Path.Combine(server_path, root));
            else
                dir = new DirectoryInfo(Path.Combine(server_path, path));
            if (!dir.Exists) {
                dir.Create();
            }
            string current = Path.Combine(dir.FullName,
                    string.Format("{0}__discuss.xml", tv.TopicName));
            File.WriteAllText(current, tv.ToXml());
            string name = Path.Combine(dir.FullName,
                    string.Format("{0}__vd{1}_{2}.xml", tv.TopicName, tv.Version.ToString("0000"),
                                    DateTime.Now.ToString("yyyy-MM-ddThh-mm-ss-fff")));
            File.WriteAllText(name, tv.ToXml());
            LuceneSearch.AddUpdateLuceneIndex(new DomainModel.SearchData(tv, "Discuss"));
        }

        public void Remove(DomainModel.TopicVersion tv)
        {
            throw new NotImplementedException();
        }

        public void Update(DomainModel.TopicVersion tv)
        {
            DirectoryInfo dir;
            if (currentDir == "WikiDir" && path == string.Empty)
                dir = new DirectoryInfo(Path.Combine(server_path, root));
            else
                dir = new DirectoryInfo(Path.Combine(server_path, path));
            string current = Path.Combine(dir.FullName,
                    string.Format("{0}__discuss.xml", tv.TopicName));
            File.WriteAllText(current, tv.ToXml(), Encoding.UTF8);
            FileInfo version = (from FileInfo file in dir.GetFiles() where file.Name.StartsWith(tv.TopicName + "__vd" + tv.Version.ToString("0000")) select file).First();
            string name = Path.Combine(dir.FullName, string.Format("{0}", version));
            File.WriteAllText(name, tv.ToXml(), Encoding.UTF8);
            LuceneSearch.AddUpdateLuceneIndex(new DomainModel.SearchData(tv, "Discuss"));
        }

        public void RemoveWikiTopic(string topicName)
        {
            DirectoryInfo dir;
            if (currentDir == "WikiDir" && path == string.Empty) {
                dir = new DirectoryInfo(Path.Combine(server_path, root));
                LuceneSearch.ClearLuceneIndexRecord("Discuss:" + root + "." + topicName);
            }
            else {
                dir = new DirectoryInfo(Path.Combine(server_path, path));
                LuceneSearch.ClearLuceneIndexRecord("Discuss:" + path + "." + topicName);
            }
            string current = Path.Combine(dir.FullName,
                    string.Format("{0}__discuss.xml", topicName));
            if (File.Exists(current)) File.Delete(current);
        }


        public DomainModel.TopicVersion GetCurrentVersion(string pageName)
        {
            DirectoryInfo dir;
            if (currentDir == "WikiDir" && path == string.Empty)
                dir = new DirectoryInfo(Path.Combine(server_path, root));
            else
                dir = new DirectoryInfo(Path.Combine(server_path, path));
            if (dir.Exists) {
                FileInfo cvf = (from FileInfo file in dir.GetFiles()
                                where file.Name == (pageName + "__discuss.xml")
                                orderby file.CreationTime descending
                                select file).FirstOrDefault();
                if (cvf != null) {
                    return new DomainModel.TopicVersion(File.ReadAllText(cvf.FullName));
                }
                else {
                    return null;
                }
            }
            else {
                return null;
            }
        }

        public void WikiTopicLockAction(string pageName, string action)
        {
            string filePath;
            if (currentDir == "WikiDir" && path == string.Empty)
                filePath = Path.Combine(server_path, root, pageName);
            else
                filePath = Path.Combine(server_path, path, pageName);
            if (action.ToLower() == "lock") {
                File.SetAttributes(filePath, File.GetAttributes(filePath) | FileAttributes.ReadOnly);
            }
            else if (action.ToLower() == "unlock") {
                File.SetAttributes(filePath, File.GetAttributes(filePath) & ~FileAttributes.ReadOnly);
            }
        }


        public bool TopicIsLocked(string pageName)
        {
            string filePath;
            if (currentDir == "WikiDir" && path == string.Empty)
                filePath = Path.Combine(server_path, root, pageName);
            else
                filePath = Path.Combine(server_path, path, pageName);
            bool IsLocked = ((File.GetAttributes(filePath) & FileAttributes.ReadOnly) == FileAttributes.ReadOnly);
            return IsLocked;
        }


        public DomainModel.TopicVersion GetSpecificVersion(string pageName, int version)
        {
            DirectoryInfo dir;
            if (currentDir == "WikiDir" && path == string.Empty)
                dir = new DirectoryInfo(Path.Combine(server_path, root));
            else
                dir = new DirectoryInfo(Path.Combine(server_path, path));
            if (dir.Exists) {
                FileInfo cvf = (from FileInfo file in dir.GetFiles()
                                where file.Name.Contains(pageName + "__v" + version.ToString("0000"))
                                select file).FirstOrDefault();
                if (cvf != null) {
                    return new DomainModel.TopicVersion(File.ReadAllText(cvf.FullName));
                }
                else {
                    return null;
                }
            }
            else {
                return null;
            }
        }

        public DomainModel.TopicVersion GetSpecificVersion(string fileName)
        {
            DirectoryInfo dir;
            if (currentDir == "WikiDir" && path == string.Empty)
                dir = new DirectoryInfo(Path.Combine(server_path, root));
            else
                dir = new DirectoryInfo(Path.Combine(server_path, path, currentDir));
            if (dir.Exists) {
                string name = Path.Combine(root, path, currentDir, fileName);
                FileInfo cvf = new FileInfo(name);
                if (cvf != null) {
                    return new DomainModel.TopicVersion(File.ReadAllText(cvf.FullName));
                }
                return null;
            }
            return null;
        }


        public int GetTopicCurrentVersionNumber(string pageName)
        {
            int version = 0;
            DirectoryInfo dir;
            if (currentDir == "WikiDir" && path == string.Empty)
                dir = new DirectoryInfo(Path.Combine(server_path, root));
            else
                dir = new DirectoryInfo(Path.Combine(server_path, path, currentDir));
            if (dir.Exists) {
                FileInfo cvf = (from FileInfo file in dir.GetFiles()
                                where file.Name == (pageName + "__discuss.xml")
                                orderby file.CreationTime descending
                                select file).FirstOrDefault();
                if (cvf != null) {
                    DomainModel.TopicVersion tv = new DomainModel.TopicVersion(File.ReadAllText(cvf.FullName));
                    version = tv.Version;
                }
            }
            return version;
        }

        public DomainModel.WikiDirectory GetWikiDirectoryInfo(string fullPath)
        {
            string path = string.Empty;
            int server_part = fullPath.LastIndexOf("LynxWiki");
            server_path = fullPath.Substring(0, server_part + 8);
            int startPath = root.Length;
            this.path = string.Empty;
            int endPath = fullPath.LastIndexOf(@"\") + 1;
            if (endPath - startPath > server_part) {
                this.path = fullPath.Substring(fullPath.LastIndexOf(this.root));
            }
            this.currentDir = string.Empty;
            if (endPath > 3) {
                this.currentDir = fullPath.Substring(endPath);
            }
            string dirName = this.currentDir;
            DirectoryInfo dir = new DirectoryInfo(fullPath);
            if (dir.Exists) {
                FileInfo file;
                if (dirName == "WikiDir" && path == string.Empty)
                    file = new FileInfo(Path.Combine(server_path, root + ".xml"));
                else
                    file = new FileInfo(fullPath + ".xml");
                if (file.Exists) {
                    return new DomainModel.WikiDirectory(File.ReadAllText(file.FullName));
                }
                else {
                    return null;
                }
            }
            else {
                return null;
            }
        }

    }
}
